/**
 * 弹幕绘制器 - 负责弹幕的渲染和绘制
 */
import type { ActiveBarrage, BarrageConfig, DetectionArea } from '../../types'
import type { VideoHelper } from '../utils/VideoHelper'

/**
 * 骨架连接定义 - MediaPipe Pose 完整版 (33个关键点)
 * 
 * 关键点索引说明：
 * 0: 鼻子
 * 1-10: 面部（眼睛、耳朵、嘴巴）
 * 11-16: 上肢（肩、肘、腕）
 * 17-22: 手部（手指尖）
 * 23-28: 下肢（臀、膝、踝）
 * 29-32: 脚部（脚跟、脚尖）
 */
const SKELETON_CONNECTIONS = [
  // === 面部连接 (Face) ===
  [0, 1], [1, 2], [2, 3],   // 右眼
  [0, 4], [4, 5], [5, 6],   // 左眼
  [0, 9], [9, 10],          // 鼻子到嘴巴
  
  // === 躯干核心连接 (Torso Core) ===
  [0, 7], [0, 8],           // 鼻子到耳朵
  [7, 11], [8, 12],         // 耳朵到肩膀
  [11, 12],                 // 肩膀横线
  [11, 23], [12, 24],       // 肩膀到臀部
  [23, 24],                 // 臀部横线
  
  // === 左臂连接 (Left Arm) ===
  [11, 13], [13, 15],       // 左肩 -> 左肘 -> 左腕
  
  // === 右臂连接 (Right Arm) ===
  [12, 14], [14, 16],       // 右肩 -> 右肘 -> 右腕
  
  // === 左手连接 (Left Hand) ===
  [15, 17],                 // 左腕 -> 左小指
  [15, 19],                 // 左腕 -> 左食指
  [15, 21],                 // 左腕 -> 左拇指
  [17, 19],                 // 左小指 <-> 左食指
  
  // === 右手连接 (Right Hand) ===
  [16, 18],                 // 右腕 -> 右小指
  [16, 20],                 // 右腕 -> 右食指
  [16, 22],                 // 右腕 -> 右拇指
  [18, 20],                 // 右小指 <-> 右食指
  
  // === 左腿连接 (Left Leg) ===
  [23, 25], [25, 27],       // 左臀 -> 左膝 -> 左踝
  
  // === 右腿连接 (Right Leg) ===
  [24, 26], [26, 28],       // 右臀 -> 右膝 -> 右踝
  
  // === 左脚连接 (Left Foot) ===
  [27, 29],                 // 左踝 -> 左脚跟
  [27, 31],                 // 左踝 -> 左脚尖
  [29, 31],                 // 左脚跟 <-> 左脚尖
  
  // === 右脚连接 (Right Foot) ===
  [28, 30],                 // 右踝 -> 右脚跟
  [28, 32],                 // 右踝 -> 右脚尖
  [30, 32],                 // 右脚跟 <-> 右脚尖
]

/**
 * 弹幕绘制器类
 */
export class BarrageDrawer {
  private ctx: CanvasRenderingContext2D
  private canvas: HTMLCanvasElement
  private videoHelper: VideoHelper
  private video?: HTMLVideoElement

  constructor(
    ctx: CanvasRenderingContext2D,
    canvas: HTMLCanvasElement,
    videoHelper: VideoHelper,
    video?: HTMLVideoElement
  ) {
    this.ctx = ctx
    this.canvas = canvas
    this.videoHelper = videoHelper
    this.video = video
  }

  /**
   * 更新视频元素
   */
  updateVideo(video?: HTMLVideoElement): void {
    this.video = video
    this.videoHelper.updateVideo(video)
  }

  /**
   * 渲染单个弹幕
   */
  renderBarrage(barrage: ActiveBarrage, config: BarrageConfig, fallbackMode: boolean, fallbackOpacity: number): void {
    // 🆕 优先使用最新的全局透明度配置，实现实时配置更新
    let opacity = config.opacity !== undefined ? config.opacity : (barrage.opacity || 1)
    
    // 备用模式下降低透明度
    if (fallbackMode) {
      opacity *= fallbackOpacity
    }
    
    // 🆕 优先使用最新的字体大小配置，实现实时配置更新
    const fontSize = config.fontSize !== undefined ? config.fontSize : (barrage.fontSize || 20)
    
    this.ctx.globalAlpha = opacity
    this.ctx.font = `bold ${fontSize}px sans-serif`
    this.ctx.lineJoin = 'round'
    this.ctx.lineWidth = Math.max(2, fontSize * 0.1)
    
    // 描边
    this.ctx.strokeStyle = 'rgba(0, 0, 0, 0.8)'
    this.ctx.strokeText(barrage.text, barrage.x, barrage.y)
    
    // 填充 - 保持原始颜色
    const fillColor = barrage.color || '#FFFFFF'
    this.ctx.fillStyle = fillColor
    this.ctx.fillText(barrage.text, barrage.x, barrage.y)
    
    // 重置所有状态，防止残留
    this.ctx.globalAlpha = 1
    this.ctx.globalCompositeOperation = 'source-over'
  }

  /**
   * 渲染调试信息
   */
  renderDebugInfo(
    activeBarrages: ActiveBarrage[],
    queueLength: number,
    config: BarrageConfig,
    tracks: any[],
    detectionAreas: DetectionArea[],
    performanceMode: boolean,
    _fallbackMode: boolean,
    _detectionCacheSize: number,
    _cacheMaxSize: number,
    pureMaskController: any
  ): void {
    this.ctx.fillStyle = 'rgba(0, 0, 0, 0.7)'
    this.ctx.fillRect(10, 10, 240, 180)
    
    this.ctx.fillStyle = '#FFFFFF'
    this.ctx.font = '12px monospace'
    
    const maxDisplayCount = (config as any).maxDisplayCount || config.maxBarrages || 50
    this.ctx.fillText(`活跃弹幕: ${activeBarrages.length}/${maxDisplayCount}`, 15, 25)
    this.ctx.fillText(`队列弹幕: ${queueLength}`, 15, 40)
    this.ctx.fillText(`轨道数: ${config.trackCount || 8}`, 15, 55)
    this.ctx.fillText(`速度: ${config.speed || 200}px/s`, 15, 70)
    this.ctx.fillText(`检测区域: ${detectionAreas.length}`, 15, 85)
    this.ctx.fillText(`性能模式: ${performanceMode ? '开启' : '关闭'}`, 15, 100)
    
    // 显示蒙版状态
    const pureMaskConfig = pureMaskController.getConfig()
    this.ctx.fillText(`蒙版模式: 纯蒙版`, 15, 115)
    this.ctx.fillText(`蒙版效果: ${pureMaskConfig.enabled ? '开启' : '关闭'}`, 15, 130)
    this.ctx.fillText(`透明度: ${(pureMaskConfig.maskOpacity * 100).toFixed(0)}%`, 15, 145)
    this.ctx.fillText(`检测状态: ${config.faceDetection ? '真实检测' : '模拟区域'}`, 15, 175)
    
    // 显示当前弹幕的蒙版状态
    const maskedBarrages = activeBarrages.filter((b: ActiveBarrage) => b.maskOpacity !== undefined && b.maskOpacity < 1.0)
    this.ctx.fillText(`蒙版弹幕: ${maskedBarrages.length}/${activeBarrages.length}`, 15, 190)
    
    // 渲染轨道
    this.renderTracks(tracks)
    
    // 渲染检测区域
    this.renderDetectionAreas(detectionAreas, config)
  }

  /**
   * 渲染轨道
   */
  private renderTracks(tracks: any[]): void {
    tracks.forEach(track => {
      this.ctx.strokeStyle = track.occupied ? 'rgba(255, 0, 0, 0.3)' : 'rgba(0, 255, 0, 0.3)'
      this.ctx.lineWidth = 1
      this.ctx.beginPath()
      this.ctx.moveTo(0, track.y)
      this.ctx.lineTo(this.canvas.width, track.y)
      this.ctx.stroke()
    })
  }

  /**
   * 渲染检测区域（绘制骨架线）
   */
  renderDetectionAreas(detectionAreas: DetectionArea[], config: BarrageConfig): void {
    detectionAreas.forEach(area => {
      // 如果有关键点，绘制人体骨架和轮廓
      if (area.keyPoints && area.keyPoints.length > 0) {
        // 计算坐标转换比例（从视频原始尺寸到Canvas显示尺寸）
        const videoRect = this.videoHelper.getVideoDisplayRect()
        const scaleX = videoRect.width / (this.video?.videoWidth || 1)
        const scaleY = videoRect.height / (this.video?.videoHeight || 1)
        
        // 转换关键点坐标
        const points = area.keyPoints.map(point => ({
          x: point.x * scaleX,
          y: point.y * scaleY
        }))
        
        // 只在配置启用时绘制骨架可视化
        if (config.showSkeleton !== false) {
          this.renderSkeleton(points)
          this.renderKeyPoints(points)
          this.renderContour(points)
          this.renderLabel(points)
        }
      }
    })
  }

  /**
   * 绘制骨架连线
   */
  private renderSkeleton(points: Array<{ x: number; y: number }>): void {
    this.ctx.save()
    this.ctx.shadowColor = 'rgba(0, 255, 255, 0.8)'
    this.ctx.shadowBlur = 10
    this.ctx.strokeStyle = 'rgba(0, 255, 255, 0.6)'
    this.ctx.lineWidth = 2
    
    SKELETON_CONNECTIONS.forEach(([i, j]) => {
      if (points[i] && points[j]) {
        this.ctx.beginPath()
        this.ctx.moveTo(points[i].x, points[i].y)
        this.ctx.lineTo(points[j].x, points[j].y)
        this.ctx.stroke()
      }
    })
    this.ctx.restore()
  }

  /**
   * 绘制关键点
   */
  private renderKeyPoints(points: Array<{ x: number; y: number }>): void {
    this.ctx.save()
    this.ctx.shadowColor = 'rgba(255, 255, 0, 1)'
    this.ctx.shadowBlur = 8
    this.ctx.fillStyle = 'rgba(255, 255, 0, 0.9)'
    points.forEach(point => {
      if (point) {
        this.ctx.beginPath()
        this.ctx.arc(point.x, point.y, 4, 0, Math.PI * 2)
        this.ctx.fill()
      }
    })
    this.ctx.restore()
  }

  /**
   * 绘制外轮廓（凸包）
   */
  private renderContour(points: Array<{ x: number; y: number }>): void {
    this.ctx.save()
    this.ctx.shadowColor = 'rgba(0, 255, 255, 0.8)'
    this.ctx.shadowBlur = 15
    this.ctx.strokeStyle = 'rgba(0, 255, 255, 0.9)'
    this.ctx.lineWidth = 3
    
    const hull = this.computeConvexHull(points)
    if (hull.length > 2) {
      this.ctx.beginPath()
      this.ctx.moveTo(hull[0].x, hull[0].y)
      hull.forEach(point => {
        this.ctx.lineTo(point.x, point.y)
      })
      this.ctx.closePath()
      this.ctx.stroke()
    }
    this.ctx.restore()
  }

  /**
   * 绘制标签
   */
  private renderLabel(points: Array<{ x: number; y: number }>): void {
    const headPoint = points[0] // 鼻子位置
    if (headPoint) {
      this.ctx.fillStyle = 'rgba(0, 255, 255, 0.8)'
      this.ctx.fillRect(headPoint.x - 40, headPoint.y - 30, 80, 18)
      this.ctx.fillStyle = '#000000'
      this.ctx.font = 'bold 12px Arial'
      this.ctx.fillText('🎯 人物', headPoint.x - 35, headPoint.y - 16)
    }
  }

  /**
   * 计算凸包（Graham扫描算法）
   */
  private computeConvexHull(points: Array<{ x: number; y: number }>): Array<{ x: number; y: number }> {
    if (points.length < 3) return points

    // 找到最下面的点（y最大，如果y相同则x最小）
    let bottom = points[0]
    for (const p of points) {
      if (p.y > bottom.y || (p.y === bottom.y && p.x < bottom.x)) {
        bottom = p
      }
    }

    // 按极角排序
    const sorted = points
      .filter(p => p !== bottom)
      .sort((a, b) => {
        const angleA = Math.atan2(a.y - bottom.y, a.x - bottom.x)
        const angleB = Math.atan2(b.y - bottom.y, b.x - bottom.x)
        return angleA - angleB
      })

    const hull: Array<{ x: number; y: number }> = [bottom]

    for (const point of sorted) {
      while (hull.length >= 2) {
        const p1 = hull[hull.length - 2]
        const p2 = hull[hull.length - 1]
        
        // 计算叉积
        const cross = (p2.x - p1.x) * (point.y - p1.y) - (p2.y - p1.y) * (point.x - p1.x)
        
        if (cross <= 0) {
          hull.pop()
        } else {
          break
        }
      }
      hull.push(point)
    }

    // 🆕 对凸包进行膨胀处理，增加安全边距
    return this.expandConvexHull(hull, 15) // 默认膨胀 15 像素
  }

  /**
   * 凸包膨胀算法 - 沿法线方向扩展凸包边界
   * @param hull 原始凸包顶点数组
   * @param margin 膨胀边距（像素）
   * @returns 膨胀后的凸包
   */
  private expandConvexHull(
    hull: Array<{ x: number; y: number }>, 
    margin: number
  ): Array<{ x: number; y: number }> {
    if (hull.length < 3 || margin <= 0) return hull

    // 计算凸包中心点
    const center = hull.reduce(
      (acc, p) => ({ x: acc.x + p.x, y: acc.y + p.y }),
      { x: 0, y: 0 }
    )
    center.x /= hull.length
    center.y /= hull.length

    // 对每个顶点沿着从中心到顶点的方向外推
    return hull.map(point => {
      // 计算从中心到顶点的向量
      const dx = point.x - center.x
      const dy = point.y - center.y
      
      // 计算向量长度
      const length = Math.sqrt(dx * dx + dy * dy)
      
      // 归一化向量并乘以膨胀边距
      if (length > 0) {
        const ratio = (length + margin) / length
        return {
          x: center.x + dx * ratio,
          y: center.y + dy * ratio
        }
      }
      
      return point
    })
  }

  /**
   * 应用人物蒙版（擦除被人物覆盖的弹幕部分）
   */
  applyPersonMask(detectionAreas: DetectionArea[]): void {
    if (detectionAreas.length === 0) return

    // 保存当前状态
    this.ctx.save()

    // 切换到"擦除"模式
    this.ctx.globalCompositeOperation = 'destination-out'
    this.ctx.fillStyle = 'rgba(0, 0, 0, 1)' // 完全不透明，用于擦除

    // 对每个检测区域绘制蒙版
    detectionAreas.forEach(area => {
      if (area.keyPoints && area.keyPoints.length > 0) {
        // 计算坐标转换比例（从视频原始尺寸到Canvas显示尺寸）
        const videoRect = this.videoHelper.getVideoDisplayRect()
        const scaleX = videoRect.width / (this.video?.videoWidth || 1)
        const scaleY = videoRect.height / (this.video?.videoHeight || 1)

        // 转换关键点坐标
        const scaledPoints = area.keyPoints.map(point => ({
          x: point.x * scaleX,
          y: point.y * scaleY
        }))

        // 计算凸包
        const hull = this.computeConvexHull(scaledPoints)

        if (hull.length > 2) {
          // 绘制凸包路径（这会擦除这个区域的弹幕）
          this.ctx.beginPath()
          this.ctx.moveTo(hull[0].x, hull[0].y)
          hull.forEach(point => {
            this.ctx.lineTo(point.x, point.y)
          })
          this.ctx.closePath()
          this.ctx.fill() // 填充会擦除这个区域
        }
      }
    })

    // 恢复正常绘制模式
    this.ctx.globalCompositeOperation = 'source-over'
    this.ctx.restore()
  }

  /**
   * 强制清理canvas
   */
  forceCleanCanvas(): void {
    // 保存当前状态
    this.ctx.save()
    
    // 重置所有变换和样式
    this.ctx.setTransform(1, 0, 0, 1, 0, 0)
    this.ctx.globalCompositeOperation = 'source-over'
    this.ctx.globalAlpha = 1.0
    
    // 清空整个canvas
    this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
    
    // 用透明色填充，确保完全清空
    this.ctx.fillStyle = 'rgba(0, 0, 0, 0)'
    this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height)
    
    // 恢复状态
    this.ctx.restore()
    
    // 重新设置正确的变换
    const dpr = window.devicePixelRatio || 1
    this.ctx.setTransform(dpr, 0, 0, dpr, 0, 0)
    this.ctx.textBaseline = 'top'
  }
}

